package logger

import (
	"net/http"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var zapLogger *zap.Logger
var zapSugaredLogger *zap.SugaredLogger
var zapLevel zap.AtomicLevel
var globalFields = make(map[string]interface{})

func init() {
	conf := Config{
		LogLevel:  "debug",
		IsConsole: true,
	}
	InitLogger(conf)
}

func InitLogger(config Config) error {
	_Config = config
	var err error
	zapLogger, err = NewZapLogger(config)
	if err != nil {
		return err
	}
	fields := make([]zap.Field, 0, len(globalFields))
	for k, v := range globalFields {
		fields = append(fields, zap.Any(k, v))
	}
	zapLogger = zapLogger.With(fields...)
	zapSugaredLogger = zapLogger.WithOptions(zap.AddCaller(), zap.AddCallerSkip(1)).Sugar()
	return nil
}

func NewZapLogger(config Config) (*zap.Logger, error) {
	zapLevel, err := initZapLevel(config.LogLevel)
	if err != nil {
		return nil, err
	}
	return initZap(config, zapLevel), nil
}

func Debug(v ...interface{}) {
	zapSugaredLogger.Debug(v...)
}

func Debugf(f string, v ...interface{}) {
	zapSugaredLogger.Debugf(f, v...)
}

func Info(v ...interface{}) {
	zapSugaredLogger.Info(v...)
}

func Infof(f string, v ...interface{}) {
	zapSugaredLogger.Infof(f, v...)
}

func Warn(v ...interface{}) {
	zapSugaredLogger.Warn(v...)
}

func Warnf(f string, v ...interface{}) {
	zapSugaredLogger.Warnf(f, v...)
}

func Error(v ...interface{}) {
	zapSugaredLogger.Error(v...)
}

func Errorf(f string, v ...interface{}) {
	zapSugaredLogger.Errorf(f, v...)
}

func Panic(v ...interface{}) {
	zapSugaredLogger.Panic(v...)
}

func Panicf(f string, v ...interface{}) {
	zapSugaredLogger.Panicf(f, v...)
}

func Fatal(v ...interface{}) {
	zapSugaredLogger.Fatal(v...)
}

func Fatalf(f string, v ...interface{}) {
	zapSugaredLogger.Fatalf(f, v...)
}

func Trace(tag string, pairs Pairs) {
	var fields []interface{}
	for _, pair := range pairs {
		fields = append(fields, zap.Any(pair.Key, pair.Value))
	}
	zapSugaredLogger.With(fields...).Info(tag)
}

func LevelServeHTTP(w http.ResponseWriter, r *http.Request) {
	zapLevel.ServeHTTP(w, r)
}

func GetLevel() zapcore.Level {
	return zapLevel.Level()
}

func SetLevel(l int) {
	zapLevel.SetLevel(zapcore.Level(l))
}

func AddGlobalFields(key string, value interface{}) {
	globalFields[key] = value
}
